package com.atguigu.gmall.order.service.impl;

import com.alibaba.fastjson.JSONObject;
import com.atguigu.gmall.common.constant.RedisConst;
import com.atguigu.gmall.common.util.HttpClientUtil;
import com.atguigu.gmall.model.cart.CartInfo;
import com.atguigu.gmall.model.enums.OrderStatus;
import com.atguigu.gmall.model.enums.ProcessStatus;
import com.atguigu.gmall.model.order.OrderDetail;
import com.atguigu.gmall.model.order.OrderInfo;
import com.atguigu.gmall.mq.config.MqConst;
import com.atguigu.gmall.order.mapper.CartInfoMapper;
import com.atguigu.gmall.order.mapper.OrderDetailMapper;
import com.atguigu.gmall.order.mapper.OrderInfoMapper;
import com.atguigu.gmall.order.service.OrderInfoService;
import com.atguigu.gmall.product.client.ProductFeignClient;
import com.atguigu.gmall.service.RabbitService;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.math.BigDecimal;
import java.util.*;
import java.util.stream.Collectors;

/**
 * @author ：MJS
 * @date ：Created in 2021/5/25  9:43
 * @description：TODO
 */
@Service
@SuppressWarnings("all")
public class OrderInfoServiceImpl implements OrderInfoService {

    @Autowired
    private ProductFeignClient productFeignClient;
    @Autowired
    private OrderInfoMapper orderInfoMapper;
    @Autowired
    private CartInfoMapper cartInfoMapper;
    @Autowired
    private OrderDetailMapper orderDetailMapper;
    @Autowired
    private RedisTemplate redisTemplate;
    @Autowired
    private RabbitService rabbitService;
    @Value("${ware.url}")
    private String wareUrl;
    //校验库存
    @Override
    public boolean hasStock(Long skuId, Integer skuNum) {
        //有货 ：实际库存-锁定库存>=购买的数量
        //无货： 实际库存-锁定库存<购买的数量
        //因为没有注册到注册中心，所以使用HttpClient
        String s = HttpClientUtil.doGet(wareUrl + "/hasStock?skuId=" + skuId + "&num=" + skuNum);
        //windows10  hosts配置 www.gware.com
        return "1".equals(s);//跟1相等 为true  否则为false
    }
    //保存订单
    @Override
    @Transactional
    public Long saveOrder(OrderInfo orderInfo) {
        //1.订单表即订单主表  为1：N中的1
        //订单状态
        orderInfo.setOrderStatus(OrderStatus.UNPAID.name());
        //订单交易编号  防止重复   加上时间戳+三位随机数
        String outTradeNo="ATGUIGU"+System.currentTimeMillis()+new Random().nextInt(1000);
        orderInfo.setOutTradeNo(outTradeNo);
        //订单描述(支付原因)
        List<OrderDetail> orderDetailList = orderInfo.getOrderDetailList();
        StringBuilder sb=new StringBuilder();
        for (OrderDetail orderDetail : orderDetailList) {
            sb.append(orderDetail.getSkuName()).append(" ");
            //重新查询商品清单的金额
            BigDecimal price = productFeignClient.getPrice(orderDetail.getSkuId());
            orderDetail.setOrderPrice(price);
        }
        //进行判断  订单描述放多少个字    100字以内  全要  超过100字 只要100字
        if(sb.length()>100){
            //放入到订单描述中
            orderInfo.setTradeBody(sb.toString().substring(0,100));
        }else{
            orderInfo.setTradeBody(sb.toString());
        }
        //创建时间  当前时间
        Calendar calendar=Calendar.getInstance();
        orderInfo.setCreateTime(calendar.getTime());
        //失效时间  2个小时    在创建时间的基础上设置两个小时
        calendar.add(Calendar.HOUR,2);
        orderInfo.setExpireTime(calendar.getTime());//两个小时的时间
        //进度状态
        orderInfo.setProcessStatus(ProcessStatus.UNPAID.name());
        //重新计算   总金额
        orderInfo.sumTotalAmount();
        //保存订单
        orderInfoMapper.insert(orderInfo);//返回ID值
        //数组ID  专门用来放skuId
        List<String>skuIdList=new ArrayList<>(orderDetailList.size());
        //2.订单详情表  商品清单  有多个
        orderDetailList.forEach(orderDetail -> {
            //订单主表的Id
            orderDetail.setOrderId(orderInfo.getId());
            //库存ID
           skuIdList.add(String.valueOf(orderDetail.getSkuId()));//Long变字符串
            //保存订单详情
            orderDetailMapper.insert(orderDetail);
        });
        //3.删除购物车中已经购买的商品
        QueryWrapper<CartInfo>queryWrapper=new QueryWrapper<>();
        queryWrapper.eq("user_id",orderInfo.getUserId());
        queryWrapper.in("sku_id",skuIdList);
        cartInfoMapper.delete(queryWrapper);//批量删除数据库
        //删除缓存中的数据
        String cacheKey= RedisConst.USER_KEY_PREFIX+orderInfo.getUserId()+RedisConst.USER_CART_KEY_SUFFIX;
        redisTemplate.opsForHash().delete(cacheKey,skuIdList.toArray());//skuIdList.toArray()必须转成数组  否则会报错
        //4.MQ延迟消息 完成  订单过期后的取消操作  起始时间   定时器  2小时 10点有会
        //基于插件的   设置的为30分钟
        rabbitService.sendDelayMessage(MqConst.EXCHANGE_DIRECT_ORDER_CANCEL,
                MqConst.ROUTING_ORDER_CANCEL,
                orderInfo.getId(),
                MqConst.DELAY_TIME);
        return orderInfo.getId();//返回订单ID
    }

    //根据订单id查询订单对象
    //只查询主表
    @Override
    public OrderInfo getOrderInfo(Long orderId) {
        return orderInfoMapper.selectById(orderId);
    }

    //根据订单id查询订单对象
    public OrderInfo getOrderInfoAndDetailList(Long orderId) {
        OrderInfo orderInfo = orderInfoMapper.selectById(orderId);
        if(null !=orderInfo ){
            QueryWrapper<OrderDetail>queryWrapper=new QueryWrapper<>();
            queryWrapper.eq("order_id",orderId);
            List<OrderDetail> orderDetailList = orderDetailMapper.selectList(queryWrapper);
            orderInfo.setOrderDetailList(orderDetailList);
        }
        return orderInfo;
    }
    //取消订单
    @Override
    public void cancelOrder(Long orderId) {
        //1.查询订单  只能未支付状态 才会取消订单  其他状态不取消
        OrderInfo orderInfo = orderInfoMapper.selectById(orderId);
        if(null !=orderInfo && orderInfo.getOrderStatus().equals(OrderStatus.UNPAID.name())){
            //发消息通知支付微服务  关闭支付宝交易
           //关闭支付宝的交易
            //alipay.trade.close  统一收单交易关闭接口

           //取消订单
            System.out.println("取消订单成功");
            orderInfo.setOrderStatus(OrderStatus.CLOSED.name());
            orderInfo.setProcessStatus(ProcessStatus.CLOSED.name());
            //关闭支付宝交易功能---调用支付宝关闭接口
            //修改
            orderInfoMapper.updateById(orderInfo);
        }
    }

    //更新订单
    @Override
    public void updateOrder(String orderId, ProcessStatus processStatus) {
        //创建订单对象
        OrderInfo orderInfo = new OrderInfo();
        orderInfo.setId(Long.parseLong(orderId));
        //设置订单状态
        orderInfo.setOrderStatus(processStatus.getOrderStatus().name());
        //设置进度状态
        orderInfo.setProcessStatus(processStatus.name());
        orderInfoMapper.updateById(orderInfo);
    }

    //更新订单
    @Override
    public void updateOrder(Long orderId) {
        //幂等性问题
        OrderInfo orderInfo = getOrderInfo(orderId);
        if(null !=orderInfo && orderInfo.getOrderStatus().equals(OrderStatus.UNPAID.name())){
            //支付状态改为已支付
            orderInfo.setOrderStatus(OrderStatus.PAID.name());
            //进度状态改为已支付
            orderInfo.setProcessStatus(ProcessStatus.PAID.name());
            //更新订单
            orderInfoMapper.updateById(orderInfo);
        }
    }
    //发消息给库存系统
    @Override
    public void sendOrderStatus(Long orderId) {
        //幂等性问题
        OrderInfo orderInfo = getOrderInfo(orderId);
        if(null !=orderInfo && orderInfo.getOrderStatus().equals(OrderStatus.PAID.name())){
            //进度状态从已支付改为通知仓库
            orderInfo.setProcessStatus(ProcessStatus.NOTIFIED_WARE.name());
            //更新订单
            orderInfoMapper.updateById(orderInfo);
            //发消息  MQ  库存微服务
            rabbitService.sendMessage(MqConst.EXCHANGE_DIRECT_WARE_STOCK,
                    MqConst.ROUTING_WARE_STOCK,initWareOrder(orderId));
        }
    }

    //开始拆单
    @Override
    public List<OrderInfo> orderSplit(Long orderId, String wareSkuMap) {
        List<OrderInfo>orderInfoList=new ArrayList<>();
        //wareSkuMap :  [{"wareId":"1","skuIds":["2","10"]},{"wareId":"2","skuIds":["3"]}]
        //原理：1张订单 由于仓库不在一起  就变成多张订单
        //原订单   父订单
        OrderInfo originOrderInfo = getOrderInfoAndDetailList(orderId);
        //新订单  子订单
        List<Map> listMap = JSONObject.parseArray(wareSkuMap, Map.class);
        //Map :{"wareId":"1","skuIds":["2","10"]}    子订单
        //Map :{"wareId":"2","skuIds":["3"]}         子订单
        for (Map map : listMap) {
            //子订单  子订单与父订单之间  ID不同    金额不同  (子订单有父ID  父订单没有NULL)
            OrderInfo subOrderInfo = new OrderInfo();
            //所有成员变量全部复制一份  父转子
            BeanUtils.copyProperties(originOrderInfo,subOrderInfo);
            //子订单ID
            subOrderInfo.setId(null);//MySql 自动生成
            //子订单有父Id
            subOrderInfo.setParentOrderId(originOrderInfo.getId());
            //仓库ID
            subOrderInfo.setWareId(String.valueOf(map.get("wareId")));
            //创建子集合
            List<OrderDetail> subOrderDetailList=new ArrayList<>();
            //订单详情
            List<OrderDetail> orderDetailList = originOrderInfo.getOrderDetailList();
            //Map :{"wareId":"1","skuIds":["2","10"]}    子订单
            //Map :{"wareId":"2","skuIds":["3"]}         子订单
            List<String> skuIds = (List<String>)map.get("skuIds");//取到的是ID"2"  "10"
            for (OrderDetail orderDetail : orderDetailList) {
                for (String skuId : skuIds) {
                    if(orderDetail.getSkuId().equals(Long.parseLong(skuId))){
                        subOrderDetailList.add(orderDetail);
                        break;
                    }
                }
            }
            //子订单有了自己的子订单详情集合
            subOrderInfo.setOrderDetailList(subOrderDetailList);
            //新的子订单总金额
            subOrderInfo.sumTotalAmount();
            //添加一个子订单
            orderInfoList.add(subOrderInfo);
            //保存订单主表
            orderInfoMapper.insert(subOrderInfo);
            //修改订单详情表
            subOrderDetailList.forEach(subOrderDetail->{
                //外键
                subOrderDetail.setOrderId(subOrderInfo.getId());
                orderDetailMapper.updateById(subOrderDetail);
            });
        }
        //修改原订单的订单状态为已拆单
        originOrderInfo.setOrderStatus(OrderStatus.SPLIT.name());
        originOrderInfo.setProcessStatus(ProcessStatus.SPLIT.name());
        orderInfoMapper.updateById(originOrderInfo);
        return orderInfoList;
    }


    //构建库存微服务所需要的数据   重载
    @Override
    public Map initWareOrder(OrderInfo orderInfo){
        Map map=new HashMap();
        map.put("orderId",orderInfo.getId());
        map.put("consignee",orderInfo.getConsignee());
        map.put("consigneeTel",orderInfo.getConsigneeTel());
        map.put("orderComment",orderInfo.getOrderComment());
        map.put("orderBody",orderInfo.getTradeBody());
        map.put("deliveryAddress",orderInfo.getDeliveryAddress());
        map.put("paymentWay","ONLINE".equals(orderInfo.getPaymentWay())?"2":"1");
        //仓库ID
        map.put("wareId",orderInfo.getWareId());
        List<OrderDetail> orderDetailList = orderInfo.getOrderDetailList();
        List<Map>listMap=orderDetailList.stream().map(orderDetail -> {
            Map m=new HashMap();
            m.put("skuId",orderDetail.getSkuId());
            m.put("skuName",orderDetail.getSkuName());
            m.put("skuNum",orderDetail.getSkuNum());
            return m;
        }).collect(Collectors.toList());
        map.put("details",listMap);
       return map;
    }
    //构建库存微服务所需要的数据
    @Override
    public String initWareOrder(Long orderId){
        OrderInfo orderInfo = getOrderInfoAndDetailList(orderId);
        Map map=new HashMap();
        map.put("orderId",orderInfo.getId());
        map.put("consignee",orderInfo.getConsignee());
        map.put("consigneeTel",orderInfo.getConsigneeTel());
        map.put("orderComment",orderInfo.getOrderComment());
        map.put("orderBody",orderInfo.getTradeBody());
        map.put("deliveryAddress",orderInfo.getDeliveryAddress());
        map.put("paymentWay","ONLINE".equals(orderInfo.getPaymentWay())?"2":"1");
        List<OrderDetail> orderDetailList = orderInfo.getOrderDetailList();
        List<Map>listMap=orderDetailList.stream().map(orderDetail -> {
            Map m=new HashMap();
            m.put("skuId",orderDetail.getSkuId());
            m.put("skuName",orderDetail.getSkuName());
            m.put("skuNum",orderDetail.getSkuNum());
            return m;
        }).collect(Collectors.toList());
        map.put("details",listMap);
        return JSONObject.toJSONString(map);
    }

}
